package jprint.jfx.http;

import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.print.PrintException;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.ResolutionSyntax;
import javax.print.attribute.standard.PrinterResolution;
import jprint.base.AppContext;
import jprint.base.http.AbstractRequestHandler;
import jprint.base.http.Http;
import jprint.base.label.Label;
import jprint.base.label.LabelItem;
import jprint.base.label.LabelPage;
import jprint.base.label.LabelService;
import jprint.base.util.JsonUtil;
import jprint.base.util.PrintUtil;

/**
 * @author zw-zheng
 * Created on 2021-02-04
 */
class PrintHandler extends AbstractRequestHandler {

    private AppContext appContext;
    private LabelService labelService;
    private PrintService[] printServices;
    private PrintService ps;

    PrintHandler(@Nonnull AppContext appContext) {
        this.appContext = appContext;
        labelService = LabelService.getInstance(appContext);
        printServices = PrinterJob.lookupPrintServices();
        ps = PrintServiceLookup.lookupDefaultPrintService();
    }

    @Override public boolean handle(Http.HttpRequest request, Http.HttpResponse response) {
        String uri = request.uri();
        if ("/api/print-preview".equals(uri)) {
            Label label = labelService.labelFormat("default-format");
            updateLabelItems(label, request);
            preview(label, response);
            return true;
        }

        if ("/api/print".equals(uri)) {
            Label label = labelService.labelFormat("default-format");
            Map<String, String> params = updateLabelItems(label, request);
            try {
                print(label, params);
                response.setContentType("application/x-javascript")
                    .setStatus(200)
                    .write(SUCCESS_JSON);
                return true;
            } catch (PrintException | PrinterException e) {
                e.printStackTrace();
            }
        }

        return false;
    }

    @SuppressWarnings("unchecked")
    private Map<String, String> updateLabelItems(Label label, Http.HttpRequest request) {
        Map<String, String> params = new HashMap<>();
        if (Http.Method.GET == request.method()) {
            for (Map.Entry<String, List<String>> entry : request.parameters().entrySet()) {
                params.put(entry.getKey(), entry.getValue().get(0));
            }
        } else {
            params.putAll(request.bodyParams());
            if (params.size() == 1 && params.containsKey("postData")) {
                params = JsonUtil.fromJsonString(params.get("postData"), Map.class);
            }
        }
        if (!params.isEmpty()) {
            for (LabelItem item : label.getItems()) {
                String id = item.getId();
                if (params.containsKey(id)) {
                    item.setValue(params.get(id));
                    params.remove(id);
                }
            }
        }
        return params;
    }

    private void preview(Label label, Http.HttpResponse response) {
        LabelPage page = new LabelPage(label, appContext);
        response.setContentType(contentTypeOf("dummy.png"));
        response.write(new ByteArrayInputStream(page.getPngBytes()));
    }

    private void print(Label label, Map<String, String> params)
        throws PrintException, PrinterException {
        int from = Integer.parseInt(params.get("f"));
        int count = Math.max(1, Integer.parseInt(params.get("c")));
        Book book = new Book();
        PageFormat format = new PageFormat();
        for (int i = 0; i < count; i++) {
            LabelPage labelPage = new LabelPage(label, appContext, from, count);
            book.append(labelPage, format);
        }

        // 纸张设置
        Paper paper = new Paper();
        paper.setSize(PrintUtil.mm2dot(appContext.getPaperWidth(), 72),
                      PrintUtil.mm2dot(appContext.getPaperHeight(), 72));
        paper.setImageableArea(0, 0,
                               PrintUtil.mm2dot(210, 72), // A4 size
                               PrintUtil.mm2dot(297, 72) // A4 size
        );
        format.setPaper(paper);

        // 分辨率设置，jdk 11 无效！
        PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
        PrinterResolution pr = new PrinterResolution(appContext.getPrinterDPI(),
                                                     appContext.getPrinterDPI(),
                                                     ResolutionSyntax.DPI);
        pras.add(pr);

        // 打印方向设置
        // pras.add(OrientationRequested.LANDSCAPE); // 0度
        // pras.add(OrientationRequested.PORTRAIT); // 90度
        // pras.add(OrientationRequested.REVERSE_LANDSCAPE); // -90度
        // pras.add(OrientationRequested.REVERSE_PORTRAIT); // 180度

        PrinterJob job = PrinterJob.getPrinterJob();
        job.setJobName("book_print_job");
        job.setPrintService(ps);
        job.setPageable(book);
        job.print(pras);
    }
}
